
#include <stdio.h>
#include "user_wifi.h"

/* The examples use WiFi configuration that you can set via project configuration menu.

   If you'd rather not, just change the below entries to strings with
   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/

char my_wifi_ssid[32] = "myssid";
char my_wifi_pass[64] = "mypassword";
char my_wifi_ap_ip[16] = "192.168.10.25";

// #define MY_WIFI_SSID "myssid"
// #define MY_WIFI_PASS "mypassword"
// #define MY_WIFI_AP_IP "192.168.10.103"
#define MY_WIFI_CHANNEL 1
#define MY_WIFI_MAX_STA_CONN 10

/* FreeRTOS event group to signal when we are connected*/
EventGroupHandle_t s_wifi_event_group;

#define PORT 8080
char ip_str[30];

static const char *TAG = "user wifi server";

static void wifi_event_handler(void *arg, esp_event_base_t event_base,
							   int32_t event_id, void *event_data);
static esp_netif_t *user_netif_create_wifi_ap(char *ip);
static void user_netif_set_softap_ip(esp_netif_ip_info_t *ap_ip, const char *ip, const char *gw, const char *netmask);

static void wifi_event_handler(void *arg, esp_event_base_t event_base,
							   int32_t event_id, void *event_data)
{
	if (event_base == WIFI_EVENT)
	{
		ESP_LOGI(TAG, "WIFI_EVENT:%ld", event_id);
		wifi_event_ap_staconnected_t *event;
		switch (event_id)
		{
		case WIFI_EVENT_AP_START:
			ESP_LOGI(TAG, "WIFI_EVENT_AP_START");
			xEventGroupSetBits(s_wifi_event_group, WIFI_AP_START_BIT);
			break;
		case WIFI_EVENT_AP_STACONNECTED:
			event = (wifi_event_ap_staconnected_t *)event_data;
			ESP_LOGI(TAG, "station " MACSTR " join, AID=%d",
					 MAC2STR(event->mac), event->aid);
			break;
		case WIFI_EVENT_AP_STADISCONNECTED:
			event = (wifi_event_ap_stadisconnected_t *)event_data;
			ESP_LOGI(TAG, "station " MACSTR " leave, AID=%d",
					 MAC2STR(event->mac), event->aid);
			break;
		}
	}
	else if (event_base == IP_EVENT)
	{
		ESP_LOGI(TAG, "IP_EVETN:%ld", event_id);
		switch (event_id)
		{
		case IP_EVENT_AP_STAIPASSIGNED:
			ip_event_ap_staipassigned_t *event = (ip_event_got_ip_t *)event_data;
			sprintf(ip_str, "" IPSTR, IP2STR(&event->ip));
			ESP_LOGI(TAG, "%s", ip_str);
			break;
		}
	}
}

esp_netif_t *netif_ap;
esp_event_handler_instance_t wifi_even_handler;
esp_event_handler_instance_t wifi_ip_handler; // 传递ip信息

void wifi_app_task(void *pt)
{
	const char *app_task_TAG = "wifi app task";
	ESP_LOGI(app_task_TAG, "init complish");
	while (1)
	{
		user_wifi_ap_start(my_wifi_ap_ip);

		EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_AP_START_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
		if ((bits & WIFI_AP_START_BIT) != WIFI_AP_START_BIT)
			continue;

		//  wifi开启之后才可以正常获得ip
		//  如果在esp_wifi_start之前调用获取ip，获取的ip并非正确的ap的ip地址
		/***************        获取ip信息      *****************************/
		user_wifi_get_ip(netif_ap);
		/***************        获取ip信息      *****************************/

		ESP_LOGI(TAG, "user_wifi_ap_start finished. SSID:%s password:%s channel:%d",
				 my_wifi_ssid, my_wifi_pass, MY_WIFI_CHANNEL);

		xTaskCreate(tcp_server_init_task, "tcp_server", 4096 * 2, NULL, 5, NULL);
		while (1)
		{
			bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_AP_STOP_BIT | WIFI_AP_REBOOT_BIT, pdTRUE, pdFALSE, portMAX_DELAY);

			ESP_LOGI(app_task_TAG, "app task stop");
			user_wifi_ap_stop();
			if ((bits & WIFI_AP_REBOOT_BIT) == WIFI_AP_REBOOT_BIT) // 直接重启
				break;
			else if ((bits & WIFI_AP_STOP_BIT) == WIFI_AP_STOP_BIT) // 等待重启命令
			{
				while (1)
				{
					bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_AP_SOFT_START_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
					if ((bits & WIFI_AP_SOFT_START_BIT) == WIFI_AP_SOFT_START_BIT)
					{
						ESP_LOGI(app_task_TAG, "app task restart");
						break;
					}
					vTaskDelay(500 / portTICK_PERIOD_MS);
				}
				break;
			}
		}
	}
}

void user_wifi_ap_start(char *ip)
{
	s_wifi_event_group = xEventGroupCreate();
	ESP_LOGI(TAG, "wifi event group");

	ESP_ERROR_CHECK(esp_netif_init());
	ESP_LOGI(TAG, "wifi netif init");
	ESP_ERROR_CHECK(esp_event_loop_create_default());
	ESP_LOGI(TAG, "wifi even loop creat");

	// esp_netif_t *netif_ap = esp_netif_create_default_wifi_ap();		//创建默认ip的服务器
	netif_ap = user_netif_create_wifi_ap(ip); // 用户自定义的服务器

	// esp_netif_dhcps_start();esp_netif_ip_info_t ip_info;

	wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
	ESP_ERROR_CHECK(esp_wifi_init(&cfg));

	ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
														ESP_EVENT_ANY_ID,
														&wifi_event_handler,
														NULL,
														&wifi_even_handler));
	ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
														ESP_EVENT_ANY_ID,
														&wifi_event_handler,
														NULL,
														&wifi_ip_handler));
	ESP_LOGI(TAG, "wifi event handler instance register");

	wifi_config_t wifi_config = {
		.ap = {
			.ssid_len = strlen(my_wifi_ssid),
			.channel = MY_WIFI_CHANNEL,
			.max_connection = MY_WIFI_MAX_STA_CONN,
			.authmode = WIFI_AUTH_WPA_WPA2_PSK,
			.pmf_cfg = {
				.required = false,
			},
		},
	};
	strcpy((char *)wifi_config.ap.ssid, my_wifi_ssid);
	strcpy((char *)wifi_config.ap.password, my_wifi_pass);

	if (strlen(my_wifi_pass) == 0)
	{
		wifi_config.ap.authmode = WIFI_AUTH_OPEN;
	}

	ESP_LOGI(TAG, "esp wifi set mode");
	ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
	ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
	ESP_ERROR_CHECK(esp_wifi_start());
}

void user_wifi_ap_stop(void)
{
	// 取消监听事件
	esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_even_handler);
	esp_event_handler_instance_unregister(IP_EVENT, ESP_EVENT_ANY_ID, wifi_ip_handler);

	tcp_server_close(NULL);

	// 删除事件组
	// vEventGroupDelete(s_wifi_event_group);

	// 停止wifi,这个的顺序十分重要，需要按照开启时候的顺序，反着来即可
	esp_wifi_stop();						  // 停止wifi
	esp_netif_destroy_default_wifi(netif_ap); // 释放netif资源

	esp_event_loop_delete_default(); // 删除事件循环组，不可以提前。提前会导致下一次重新开启wifi，客户端无法正确获得ip地址

	esp_wifi_deinit(); // wifi重初始化，释放全部wifi资源
}

/**
 * @description: 设置指定的服务器ip，建议两个服务器ip之间的预留一定的ip位置，给客户端使用
 * @param {char} *ip[in] 设置指定的gw和ip，gw = ip;
 * @return {*}
 * @use:
 */
static esp_netif_t *user_netif_create_wifi_ap(char *ip)
{
	// esp_netif_t *netif_ap = esp_netif_create_default_wifi_ap();

	// 初始化ip信息
	char *gw = ip;
	esp_netif_ip_info_t softap_ip;
	ESP_LOGI(TAG, "wifi ap ip set");
	user_netif_set_softap_ip(&softap_ip, ip, gw, USER_WIFI_AP_DEFAULT_NETMASK);

	// 根据ip，实例化接口设置
	ESP_LOGI(TAG, "wifi get ap config");
	esp_netif_inherent_config_t cfg = USER_WIFI_AP_INHERENT_CONFIG(softap_ip);

	// 初始化wifi
	ESP_LOGI(TAG, "wifi netif create");
	esp_netif_t *netif_ap = esp_netif_create_wifi(ESP_IF_WIFI_AP, &cfg);

	ESP_LOGI(TAG, "wifi set ap default handlers");
	esp_wifi_set_default_wifi_ap_handlers();

	return netif_ap;
}
/**
 * @description: 禁止外部调用，用于改变ap的初始ip
 * @param {esp_netif_ip_info_t} *ap_ip	ap_cfg ap参数设置结构体
 * @param {char} *ip		//ip地址
 * @param {char} *gw		//gw地址 默认同ip一样
 * @param {char} *netmask	//netmask地址 默认为255.255.255.0
 * @return {*}
 * @use:
 */
static void user_netif_set_softap_ip(esp_netif_ip_info_t *ap_ip, const char *ip, const char *gw, const char *netmask)
{
	ap_ip->ip.addr = inet_addr(ip);
	ap_ip->gw.addr = inet_addr(gw);
	ap_ip->netmask.addr = inet_addr(netmask);
}

/**
 * @description: 获取ip地址，目前仅在客户端使用
 * @param {esp_netif_t} *esp_netif
 * @return {*}
 * @use:
 */
void user_wifi_get_ip(esp_netif_t *esp_netif)
{
	esp_netif_ip_info_t ip_info;
	ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif, &ip_info));
	ESP_LOGI("IP INFO", "ip info:" IPSTR, IP2STR(&ip_info.ip));
}